package com.huirui.server.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huirui.server.constant.OrderStatus;
import com.huirui.server.constant.OrderType;
import com.huirui.server.context.UserContext;
import com.huirui.server.exception.OrderNotExistsException;
import com.huirui.server.generator.OrderIdGenerator;
import com.huirui.server.mapper.OrderMapper;
import com.huirui.server.pojo.dto.ConfirmShipmentDto;
import com.huirui.server.pojo.dto.OrderCreateDto;
import com.huirui.server.pojo.dto.OrderPrepareInfoDTO;
import com.huirui.server.pojo.dto.OrderSubmitDto;
import com.huirui.server.pojo.entity.*;
import com.huirui.server.pojo.result.PageResult;
import com.huirui.server.pojo.vo.*;
import com.huirui.server.service.*;
import io.jsonwebtoken.lang.Collections;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author yujun
 * @description 针对表【t_order(订单表)】的数据库操作Service实现
 * @createDate 2025-09-27 11:27:55
 */
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
        implements OrderService {

    @Resource
    private ProductSpecificationService specificationService;

    @Resource
    private DeliveryAddressService addressService;

    @Resource
    private OrderDetailService orderDetailService;

    @Resource
    private DeliveryAddressService deliveryAddressService;

    @Resource
    private OrderDeliveryService orderDeliveryService;

    @Resource
    private ProductService productService;

    @Resource
    private UserService userService;

    @Resource
    private OrderSettingService orderSettingService;

    @Override
    public List<OrderConfirmVo> listConfirmProductInfo(List<Long> ids) {
        return baseMapper.listConfirmProductInfo(ids);
    }

    @Override
    @Transactional
    public OrderResponseVo createOrder(OrderCreateDto orderCreateDto) {
        Long userId = UserContext.getId();
        String orderNumber = OrderIdGenerator.generateId();
        Order order = new Order();
        order.setOrderNo(orderNumber);
        order.setUserId(userId);
        Map<Long, BigDecimal> priceMap = getPriceMap(orderCreateDto.getProductItemList());
        // 计算订单总金额
        BigDecimal totalAmount = calculateTotalAmount(orderCreateDto.getProductItemList(), priceMap);
        order.setTotalAmount(totalAmount);
        order.setStatus(OrderStatus.PENDING_PAYMENT);
        // 查询收货地址
        DeliveryAddress deliveryAddress = addressService
                .lambdaQuery()
                .select(
                        DeliveryAddress::getReceiverName,
                        DeliveryAddress::getReceiverPhone,
                        DeliveryAddress::getProvince,
                        DeliveryAddress::getCity,
                        DeliveryAddress::getDistrict,
                        DeliveryAddress::getDetailAddress
                )
                .eq(DeliveryAddress::getId, orderCreateDto.getDeliveryAddressId())
                .one();
        order.setReceiverName(deliveryAddress.getReceiverName());
        order.setReceiverPhone(deliveryAddress.getReceiverPhone());
        String address = deliveryAddress.getProvince()
                + deliveryAddress.getCity()
                + deliveryAddress.getDistrict()
                + deliveryAddress.getDetailAddress();
        order.setReceiverAddress(address);
        order.setCustomerNote(orderCreateDto.getNotes());
        order.setCreateTime(LocalDateTime.now());
        order.setUpdateTime(LocalDateTime.now());
        save(order);
        // 更新OrderDetail表
        List<OrderDetail> orderDetailList = new ArrayList<>();
        for (OrderCreateDto.OrderProductItem orderProductItem : orderCreateDto.getProductItemList()) {
            OrderDetail orderDetail = new OrderDetail();
            orderDetail.setOrderId(order.getId());
            orderDetail.setQuantity(Math.toIntExact(orderProductItem.quantity));
            orderDetail.setProductSpecificationId(orderProductItem.productSpecificationId);
            orderDetail.setProductPrice(priceMap.get(orderProductItem.productSpecificationId));
            orderDetailList.add(orderDetail);
        }
        orderDetailService.saveBatch(orderDetailList);
        return OrderResponseVo
                .builder()
                .orderNumber(order.getOrderNo())
                .build();
    }

    @Override
    public List<OrderResponseVo> getAllOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getAllOrderList(userId, offset, pageSize);
    }

    @Override
    public List<OrderResponseVo> getPendingPaymentOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getPendingPaymentOrderList(userId, offset, pageSize);
    }

    @Override
    public List<OrderResponseVo> getPendingReceiptOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getPendingReceiptOrderList(userId, offset, pageSize);
    }

    @Override
    public List<OrderResponseVo> getFinishedOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getFinishedOrderList(userId, offset, pageSize);
    }

    @Override
    public List<OrderResponseVo> getAfterSalesOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getAfterSalesOrderList(userId, offset, pageSize);
    }

    @Override
    public List<OrderResponseVo> getPendingDeliveryOrderList(Long page, Long pageSize) {
        Long userId = UserContext.getId();
        Long offset = (page - 1) * pageSize;
        return baseMapper.getPendingDeliveryOrderList(userId, offset, pageSize);
    }

    @Override
    public void cancelOrder(Long orderId) {
        lambdaUpdate()
                .set(Order::getStatus, OrderStatus.CANCELED)
                .eq(Order::getId, orderId)
                .update();
    }

    @Override
    public void deleteOrder(Long orderId) {
        lambdaUpdate()
                .eq(Order::getId, orderId)
                .remove();
    }

    @Override
    public OrderDetailVo getOrderDetail(Long orderId) {
        return baseMapper.getOrderDetail(orderId);
    }

    @Override
    public void updateOrderDeliveryAddress(Long id, Long orderId) {
        DeliveryAddress deliveryAddress = addressService
                .lambdaQuery()
                .select(
                        DeliveryAddress::getProvince,
                        DeliveryAddress::getCity,
                        DeliveryAddress::getDistrict,
                        DeliveryAddress::getDetailAddress,
                        DeliveryAddress::getReceiverName,
                        DeliveryAddress::getReceiverPhone
                )
                .eq(DeliveryAddress::getId, id)
                .one();
        lambdaUpdate()
                .set(Order::getReceiverName, deliveryAddress.getReceiverName())
                .set(Order::getReceiverPhone, deliveryAddress.getReceiverPhone())
                .set(Order::getUpdateTime, LocalDateTime.now())
                .set(
                        Order::getReceiverAddress,
                        deliveryAddress.getProvince()
                                + deliveryAddress.getCity()
                                + deliveryAddress.getDistrict()
                                + deliveryAddress.getDetailAddress()
                )
                .eq(Order::getId, orderId)
                .update();
    }

    @Override
    public PageResult<OrderVo> listOrderVo(Integer orderType, Integer paymentMethod, Long status, LocalDate beginTime, LocalDate endTime, Integer searchCondition, String searchValue, Integer currentPage, Integer pageSize) {
        IPage<Long> orderIdIpage = new Page<>(currentPage, pageSize);
        // 首先查询出符合条件的orderId
        orderIdIpage = baseMapper.listQueriedOrderId(orderType, paymentMethod, status, beginTime, endTime, searchCondition, searchValue, orderIdIpage);
        List<OrderVo> orderVoList = new ArrayList<>();
        if (!orderIdIpage.getRecords().isEmpty()) {
            orderVoList = baseMapper
                    .listOrderVo(orderIdIpage.getRecords());
        }
        PageResult<OrderVo> res = new PageResult<>();
        res.setRecords(orderVoList);
        res.setSize(orderIdIpage.getSize());
        res.setPages(orderIdIpage.getPages());
        res.setCurrent(orderIdIpage.getCurrent());
        res.setTotal(orderIdIpage.getTotal());
        return res;
    }

    @Override
    public OrderCountVo getBriefOrderCount() {

        return null;
    }

    @Override
    public void editMerchantNote(Long orderId, String merchantNote) {
        lambdaUpdate()
                .eq(Order::getId, orderId)
                .set(Order::getMerchantNote, merchantNote)
                .set(Order::getUpdateTime, LocalDateTime.now())
                .update();
    }

    @Override
    public void editOrderPrice(Long orderId, String actualPayment) {
        lambdaUpdate()
                .eq(Order::getId, orderId)
                .set(Order::getUpdateTime, LocalDateTime.now())
                .set(Order::getActualPayment, BigDecimal.valueOf(Double.parseDouble(actualPayment)))
                .update();
    }

    @Override
    public void closeOrder(Long orderId) {
        lambdaUpdate()
                .eq(Order::getId, orderId)
                .set(Order::getStatus, OrderStatus.CANCELED)
                .set(Order::getUpdateTime, LocalDateTime.now())
                .update();
    }

    @Override
    public HighlyDetailedOrderDetailVo getHighlyDetailedOrderDetails(Long orderId) {
        HighlyDetailedOrderDetailVo orderDetailVo = baseMapper.getHighlyDetailedOrderDetails(orderId);
        if (orderDetailVo == null) {
            throw new OrderNotExistsException("订单不存在");
        }
        orderDetailVo.setTotalNumberOfProducts((long) orderDetailVo.getOrderDetailList().size());
        return orderDetailVo;
    }

    @Override
    @Transactional
    public void confirmShipment(ConfirmShipmentDto confirmShipmentDto) {
        OrderDelivery orderDelivery = new OrderDelivery();
        orderDelivery.setOrderId(confirmShipmentDto.getOrderId());
        orderDelivery.setDeliveryType(confirmShipmentDto.getDeliveryType());
        if (orderDelivery.getDeliveryType() == 0) {
            orderDelivery.setTrackingNumber(confirmShipmentDto.getTrackingNumber());
        }
        Order order = lambdaQuery()
                .select(Order::getReceiverName, Order::getReceiverPhone, Order::getReceiverAddress)
                .eq(Order::getId, confirmShipmentDto.getOrderId())
                .one();
        orderDelivery.setDeliveryAddress(order.getReceiverAddress());
        orderDelivery.setRecipientName(order.getReceiverName());
        orderDelivery.setRecipientPhone(order.getReceiverPhone());
        orderDelivery.setCreateTime(LocalDateTime.now());
        orderDelivery.setUpdateTime(LocalDateTime.now());
        orderDeliveryService.save(orderDelivery);
        lambdaUpdate()
                .eq(Order::getId, confirmShipmentDto.getOrderId())
                .set(Order::getStatus, OrderStatus.PENDING_RECEIPT)
                .set(Order::getDeliveryTime, LocalDateTime.now())
                .set(Order::getUpdateTime, LocalDateTime.now())
                .update();
    }

    @Override
    public DeliveryInformationVo getDeliveryInformation(Long orderId) {
        DeliveryInformationVo deliveryInformationVo = new DeliveryInformationVo();
        String orderNo = lambdaQuery()
                .eq(Order::getId, orderId)
                .select(Order::getOrderNo)
                .one().getOrderNo();
        OrderDelivery orderDelivery = orderDeliveryService
                .lambdaQuery()
                .eq(OrderDelivery::getOrderId, orderId)
                .one();
        deliveryInformationVo
                .setOrderNumber(orderNo)
                .setDeliveryType(orderDelivery.getDeliveryType())
                .setTrackingNumber(orderDelivery.getTrackingNumber());
        return deliveryInformationVo;
    }

    @Override
    public void confirmReceipt(Long orderId) {
        lambdaUpdate()
                .eq(Order::getId, orderId)
                .set(Order::getStatus, OrderStatus.COMPLETED)
                .set(Order::getUpdateTime, LocalDateTime.now())
                .set(Order::getReceiveTime, LocalDateTime.now())
                .update();
    }

    @Override
    public void modifyDeliveryInformation(ConfirmShipmentDto confirmShipmentDto) {
        orderDeliveryService
                .lambdaUpdate()
                .eq(OrderDelivery::getOrderId, confirmShipmentDto.getOrderId())
                .set(OrderDelivery::getDeliveryType, confirmShipmentDto.getDeliveryType())
                .set(OrderDelivery::getUpdateTime, LocalDateTime.now())
                .set(OrderDelivery::getTrackingNumber, confirmShipmentDto.getTrackingNumber())
                .update();
    }

    @Override
    public OrderPrepareInfoVo getOrderPrepareInfo(OrderPrepareInfoDTO orderPrepareInfoDTO) {
        OrderPrepareInfoVo orderPrepareInfoVo = new OrderPrepareInfoVo();
        // 查询用户收货地址
        List<DeliveryAddress> list = deliveryAddressService
                .lambdaQuery()
                .select(
                        DeliveryAddress::getProvince,
                        DeliveryAddress::getCity,
                        DeliveryAddress::getDistrict,
                        DeliveryAddress::getDetailAddress,
                        DeliveryAddress::getReceiverPhone,
                        DeliveryAddress::getReceiverName
                )
                .eq(DeliveryAddress::getUserId, UserContext.getId())
                .orderByDesc(DeliveryAddress::getCreatedTime)
                .orderByDesc(DeliveryAddress::getIsDefault)
                .last("limit 1")
                .list();
        if (list != null && !list.isEmpty()) {
            DeliveryAddress deliveryAddress = list.getFirst();
            orderPrepareInfoVo.setReceiverProvince(deliveryAddress.getProvince());
            orderPrepareInfoVo.setReceiverCity(deliveryAddress.getCity());
            orderPrepareInfoVo.setReceiverDistrict(deliveryAddress.getDistrict());
            orderPrepareInfoVo.setReceiverAddress(deliveryAddress.getDetailAddress());
            orderPrepareInfoVo.setReceiverPhone(deliveryAddress.getReceiverPhone());
            orderPrepareInfoVo.setReceiverName(deliveryAddress.getReceiverName());
        }
        final Long[] quantity = {0L};
        List<OrderItemInfoVo> orderItemInfoVoList = new ArrayList<>();
        // 设置总价格，折扣，最终价格 TODO不同的商品计算不同的折扣
        BigDecimal totalPrice = BigDecimal.ZERO;
        BigDecimal discount = BigDecimal.ZERO;
        BigDecimal finalPrice = BigDecimal.ZERO;

        for (int i = 0; i < orderPrepareInfoDTO.getOrderPrepareInfoItems().size(); i++) {
            var orderPrepareInfoItem = orderPrepareInfoDTO.getOrderPrepareInfoItems().get(i);
            OrderItemInfoVo orderItemInfoVo = productService
                    .queryOrderPrepareInfo(orderPrepareInfoItem.getProductId(), orderPrepareInfoItem.getProductSpecificationId());
            orderItemInfoVo.setQuantity(orderPrepareInfoItem.getQuantity());
            quantity[0] += orderPrepareInfoItem.getQuantity();
            BigDecimal currentOriginalPrice = orderItemInfoVo.getOriginalPrice();
            BigDecimal currentDiscountPrice = orderItemInfoVo.getDiscountPrice();
            BigDecimal currentPromotionPrice = orderItemInfoVo.getPromotionPrice();
            totalPrice = totalPrice.add(currentOriginalPrice.multiply(new BigDecimal(orderPrepareInfoItem.getQuantity())));
            finalPrice = finalPrice.add(currentDiscountPrice.multiply(new BigDecimal(orderPrepareInfoItem.getQuantity())));
            orderItemInfoVoList.add(orderItemInfoVo);
        }
        discount = totalPrice.subtract(finalPrice);
        BigDecimal balance = userService
                .lambdaQuery()
                .eq(User::getId, UserContext.getId())
                .select(User::getBalance)
                .one()
                .getBalance();
        OrderSetting orderSetting = orderSettingService
                .lambdaQuery()
                .select(OrderSetting::getFreeShippingThreshold, OrderSetting::getShippingPrice)
                .list()
                .getFirst();
        orderPrepareInfoVo.setOrderItemInfoVoList(orderItemInfoVoList);

        // 用户余额
        orderPrepareInfoVo.setAmountBalance(balance);
        // N个商品
        orderPrepareInfoVo.setPieces(quantity[0]);
        // N中商品
        orderPrepareInfoVo.setTypes((long) orderItemInfoVoList.size());
        // 订单总价
        orderPrepareInfoVo.setTotalPrice(totalPrice);
        // 订单折扣
        orderPrepareInfoVo.setDiscount(discount);
        // 订单最终价格
        orderPrepareInfoVo.setFinalPrice(finalPrice);
        // 设置订单类型
        orderPrepareInfoVo.setOrderType(OrderType.GENERAL_ORDER);
        // 运费
        if (orderPrepareInfoVo.getFinalPrice().compareTo(orderSetting.getFreeShippingThreshold()) >= 0) {
            orderPrepareInfoVo.setShippingPrice(BigDecimal.ZERO);
        } else {
            orderPrepareInfoVo.setShippingPrice(orderSetting.getShippingPrice());
        }
        orderPrepareInfoVo.setFreeShippingThreshold(orderSetting.getFreeShippingThreshold());
        orderPrepareInfoVo.setShippingFee(orderSetting.getShippingPrice());
        return orderPrepareInfoVo;
    }

    @Override
    public OrderSubmitVo submitOrder(OrderSubmitDto orderSubmitDto) {



        return null;
    }


    private BigDecimal calculateTotalAmount(List<OrderCreateDto.OrderProductItem> orderProductItemList, Map<Long, BigDecimal> priceMap) {
        if (Collections.isEmpty(orderProductItemList)) return BigDecimal.ZERO;
        // 计算总金额
        BigDecimal totalAmount = BigDecimal.ZERO;
        for (OrderCreateDto.OrderProductItem orderProductItem : orderProductItemList) {
            BigDecimal salePrice = priceMap.get(orderProductItem.productSpecificationId);
            BigDecimal itemAccount = salePrice.multiply(BigDecimal.valueOf(orderProductItem.quantity));
            totalAmount = totalAmount.add(itemAccount);
        }
        return totalAmount.setScale(2, RoundingMode.HALF_UP);
    }

    private Map<Long, BigDecimal> getPriceMap(List<OrderCreateDto.OrderProductItem> orderProductItemList) {
        // 提取所有的商品规格Id
        List<Long> productSpecificationIds = orderProductItemList
                .stream()
                .map(item -> item.productSpecificationId)
                .toList();
        // 查询出每个规格的售价
        List<ProductSpecification> productSpecificationList = specificationService
                .lambdaQuery()
                .select(ProductSpecification::getId, ProductSpecification::getDiscountPrice)
                .in(ProductSpecification::getId, productSpecificationIds)
                .list();
        // 转换为Id-售价的映射
        return productSpecificationList
                .stream()
                .collect(
                        Collectors.toMap(
                                ProductSpecification::getId,
                                ProductSpecification::getDiscountPrice
                        )
                );
    }
}




